#include "ZAWays.h"

int CalData(int x,int y,bool pass)
{
	int data;
	__asm{
		xor eax,eax
		xor ebx,ebx
		xor ecx,ecx
		mov eax,x
		mov bx,word ptr [y]
		mov cl,byte ptr [pass]
		shl eax,17
		shl ebx,2
		or eax,ebx
		or eax,ecx
		mov dword ptr [data],eax
	}
	return data;
}

TPos CalXY(int data)
{
	TPos pos;
	__asm{
		pxor mm0,mm0
		pxor mm1,mm1
		xor eax,eax
		mov eax,data
		mov ebx,eax
		shr ebx,17
		movd mm0,ebx
		mov ebx,eax
		shl ebx,15
		shr ebx,17
		movd mm1,ebx
		psllq mm1,32
		por mm1,mm0
		movq pos,mm1
		emms
	}
	return pos;
}

bool GridPass(int data)
{
	if(data&0x0000000b)
		return false;
	else
		return true;
}

int ChackLoadGridIn(TZList *loadlist,PGrid pgrid)
{
	int i;
	PGrid lg;
	for(i=0;i<loadlist->count;i++)
	{
		lg=(PGrid)loadlist->items(i);
		if(pgrid==lg)
		{
			return i;
		}
	}
	return -1;
}

CObstruct::CObstruct()
{
	m_Grids=NULL;
	W=0;
	H=0;
	rateW=1;
	rateH=1;
	pCloseList=new TZList(100);
}

CObstruct::~CObstruct()
{
	delete pCloseList;
	DeleteObs();
}

void CObstruct::DeleteObs()
{
	int i,j;
	if(this->m_Grids!=NULL)
	{
		for(i=0;i<H;i++)
		{
			for(j=0;j<W;j++)
			{
				delete m_Grids[i][j];
			}
			delete[] m_Grids[i];
		}
		delete[] m_Grids;
		m_Grids=NULL;
	}
}

void CObstruct::CreateObs(int w, int h)
{
	int i,j,m,n,k;
	int xkey[3]={1,-1,0};
	int ykey[3]={1,-1,0};
	int key[8]={0,1,4,3,2,6,7,5};
	if(m_Grids!=NULL)
	{
		DeleteObs();
	}
	W=w;
	H=h;
	m_Grids=new PGrid*[h];
	for(i=0;i<h;i++)
	{
		m_Grids[i]=new PGrid[w];
		for(j=0;j<w;j++)
		{
			m_Grids[i][j]=new Grid;
		}
	}
	for(i=0;i<h;i++)
	{
		for(j=0;j<w;j++)
		{
			k=0;
			for(m=0;m<3;m++)
			{
				for(n=0;n<3;n++)
				{
					if(m==2 && n==2)
						continue;
					if(i+xkey[m]<0 || i+xkey[m]>=W || j+ykey[n]<0 || j+ykey[n]>=H)
					{
						m_Grids[i][j]->DirPoint[key[k]]=NULL;
						k++;
						continue;
					}
					m_Grids[i][j]->DirPoint[key[k]]=m_Grids[i+xkey[m]][j+ykey[n]];
					k++;
				}
			}
		}
	}
}

void CObstruct::SetWH(int w,int h)
{
	rateW=w;
	rateH=h;
}

void CObstruct::SetGrids(int i,int j,int x, int y, bool pass)
{
	m_Grids[i][j]->data=CalData(x,y,pass);
}

PGrid CObstruct::GetGridForPos(TPos pos)
{
	if(abs(pos.x)/rateW>W || abs(pos.y)/rateH>H)
		return NULL;
	return m_Grids[abs(pos.y)/rateH][abs(pos.x)/rateW];
}

PGrid CObstruct::GetNear(PGrid target,PGrid start)
{
	int i,minlen,templen;
	PGrid tempg,minpg;
	TPos temppos,startpos;
	minpg=NULL;
	minlen=-1;
	startpos=CalXY(start->data);
	for(i=0;i<8;i++)
	{
		tempg=target->DirPoint[i];
		if(tempg==NULL)
		{
			continue;
		}
		if(GridPass(tempg->data))
			return tempg;
		temppos=CalXY(tempg->data);
		templen=abs(temppos.x-startpos.x)+abs(temppos.y-startpos.y);
		if(minlen==-1 || minlen>=templen)
		{
			minlen=templen;
			minpg=tempg;
		}
	}
	if(minpg)
	{
		return GetNear(minpg,start);
	}
	return NULL;
}

void CObstruct::GetLoad(TZList *loadlist, PGrid start, PGrid target)
{
	int i,minlen,templen;
	PGrid tempg,minpg;
	TPos temppos,tarpos;
	
	if(start==NULL)
		return;
	for(i=0;i<8;i++)
	{
		tempg=start->DirPoint[i];
		templen=ChackLoadGridIn(loadlist,tempg);
		if(templen>=0 && templen<loadlist->count-1)
		{
			for(minlen=loadlist->count-1;minlen>templen;minlen--)
			{
				loadlist->del(minlen);
			}
		}
	}
	loadlist->add((LPVOID)start);
	pCloseList->add((LPVOID)start);
	
	tarpos=CalXY(target->data);
	minpg=NULL;
	minlen=0;
	for(i=0;i<8;i++)
	{
		tempg=start->DirPoint[i];
		if(tempg==NULL)
		{
			continue;
		}
		if(!GridPass(tempg->data))
		{
			continue;
		}
		if(ChackLoadGridIn(pCloseList,tempg)>=0)
		{
			continue;
		}
		temppos=CalXY(tempg->data);
		templen=abs(temppos.x-tarpos.x)+abs(temppos.y-tarpos.y);
		if(templen==0)
		{
			loadlist->add((LPVOID)tempg);
			pCloseList->delall();
			return;
		}
		if(minlen==0 || templen<=minlen)
		{
			minlen=templen;
			minpg=tempg;
		}
	}
	if(minpg==NULL)
	{
		pCloseList->delall();
		return;
	}
	temppos=CalXY(minpg->data);
	//printf("CloseLoad X=%d,Y=%d\n",temppos.x,temppos.y);
	return GetLoad(loadlist,minpg,target);
}